package main.model.critters;

import java.util.Random;

import main.model.critters.genetics.Chromosome;
import main.model.critters.genetics.Gene;
import main.model.critters.genetics.GeneType;
import main.model.critters.genetics.Sex;
import main.model.critters.genetics.Species;


public class CritterFactory {
	
	public static Critter randomCritter(){
		Sex sex = randomSex();
		return randomCritter(sex);
	}
	
	public static Critter randomCritter(Sex sex){
		Chromosome xchromosome = randomChromosome();
		Chromosome ychromosome = randomChromosome();
		
		Species species = new Species();
		Critter c = new Critter(xchromosome, ychromosome, species, sex);
		return c;
	}
	
	public static Critter randomHomogenousCritter(Sex sex){
		Chromosome chromosomea = randomChromosome();
		Chromosome chromosomeb = mutateChromosome(chromosomea,3);
		
		
		Species species = new Species();
		Critter c = new Critter(chromosomea, chromosomeb, species, sex);
		return c;
	}
	
	public static Chromosome randomChromosome(){
		Chromosome c = new Chromosome();
		Random random = new Random();
		for(GeneType gtype: GeneType.values()){
			Gene g = c.getGene(gtype);
			g.setDominance(random.nextInt(Gene.getGeneMax()));
			g.setEffect(random.nextInt(Gene.getGeneMax()));
			c.setGene(gtype, g);
		}
		return c;
	}
	
	public static Sex randomSex(){
		Random random = new Random();
		if(random.nextInt(2) == 0){
			return Sex.MALE;
		}else{
			return Sex.FEMALE;
		}
	}
	
	
	public static Critter breed(Critter mother, Critter father){
		if(mother.getSex() != Sex.FEMALE){
			return null;
		}
		if(father.getSex() != Sex.MALE){
			return null;
		}
		Sex sex = CritterFactory.randomSex();
		Chromosome xchromosome = generateChromosome(mother);
		Chromosome ychromosome = generateChromosome(father); 
		Species species = mother.getSpecies();
		Critter offspring = new Critter(xchromosome, ychromosome, 
				mother, father, species, sex);
		return offspring;
	}
	
	/**
	 * Takes a parent, mixes its chromosomes randomly
	 * and returns a mutated child chromosome.
	 * 
	 * @param parent
	 * @return
	 */
	public static Chromosome generateChromosome(Critter parent){
		Chromosome child = new Chromosome();
		Random random = new Random();
		for (GeneType g : GeneType.values()){
			Gene geneParent;
			if(random.nextInt(2) == 0){
				geneParent = parent.getXchromosome().getGene(g);
			}else{
				geneParent = parent.getYchromosome().getGene(g);
			}
			
			child.getGene(g).setDominance(geneParent.getDominance());
			child.getGene(g).setEffect(geneParent.getEffect());
		}
		int mutations = (child.getGene(GeneType.MUTATIONS).getEffect()/2)+1;
		return mutateChromosome(child,mutations);
	}
	
	private static Chromosome mutateChromosome(Chromosome chromosome,int mutations){
		Random random = new Random();
		Chromosome mutant = new Chromosome();
		
		for(int m = 0; m< mutations;m++){
			int r = random.nextInt(GeneType.values().length);
			int i = 0;
			
			
			for (GeneType g : GeneType.values()){
				if(i == r){
					Gene gene = chromosome.getGene(g);
					Gene mutantGene = mutant.getGene(g);
					
					int area = random.nextInt(3);
					int direction = random.nextInt(2);
					int distance = random.nextInt(4) + random.nextInt(6);
					int x;
					
					if(area == 0){x = gene.getDominance();}
					else{x = gene.getEffect();}
					
					if(direction == 0){x = x + distance;}
					else{x = x - distance;}
					
					if(area == 0){mutantGene.setDominance(x);}
					else{mutantGene.setEffect(x);}
					
					break;
				}else{i++;}
			}
		}
		return mutant;
	}
	
}
